package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/digineo/go-uci"
	"io/ioutil"
	"serialnet/app"
	"serialnet/common"
	"serialnet/model"
	"strconv"
	"strings"
)

func LoadAppConfig() (err error) {
	var (
		content []byte
		conf    model.AppConfig
	)
	filename := common.GetConfigPath() + "config_app.json"

	if content, err = ioutil.ReadFile(filename); err != nil {
		fmt.Println(err)
		return
	}

	if err = json.Unmarshal(content, &conf); err == nil {
		app.Config = &conf
		var rs232, rs485 model.SerialPara
		if LoadSerialConfig("rs232", &rs232) == nil {
			app.Config.Rs232Config = &rs232
		}
		if LoadSerialConfig("rs485", &rs485) == nil {
			app.Config.Rs485Config = &rs485
		}
	} else { // 默认值
		app.Config = &conf
		app.Config.MaxPacketSize = 1290
		app.Config.MaxWorker = 100
		app.Config.EnableLog = true
		app.Config.SaveLog = true
		app.Config.LogLevel = model.Info
		var rs232, rs485 model.SerialPara
		if LoadSerialConfig("rs232", &rs232) == nil {
			app.Config.Rs232Config = &rs232
		}
		if LoadSerialConfig("rs485", &rs485) == nil {
			app.Config.Rs485Config = &rs485
		}
		return err
	}
	return
}

func SaveAppConfig() (err error) {
	if app.Config == nil {
		return errors.New("config is nil")
	}
	content, err := json.Marshal(*app.Config)
	if err != nil {
		return err
	}

	if app.Config.Rs232Config != nil {
		_ = SaveSerialConfig("rs232", app.Config.Rs232Config)
	}
	if app.Config.Rs485Config != nil {
		_ = SaveSerialConfig("rs485", app.Config.Rs485Config)
	}

	filename := common.GetConfigPath() + "config_app.json"
	return ioutil.WriteFile(filename, content, 0664)
}

func LoadSerialConfig(section string, conf *model.SerialPara) error {
	if conf == nil {
		return errors.New("config obj is nil")
	}
	if port, ok := uci.GetLast("serial", section, "tcp_port"); ok {
		if p, err := strconv.Atoi(port); err != nil {
			return err
		} else {
			conf.ListenPort = p
		}
	}
	if led, ok := uci.GetLast("serial", section, "led"); ok {
		conf.LedIO = led
	}
	if name, ok := uci.GetLast("serial", section, "tname"); ok {
		conf.Name = name
		if !strings.Contains(conf.Name, "/dev/") {
			conf.Name = "/dev/" + conf.Name
		}
	}
	if baud, ok := uci.GetLast("serial", section, "baudrate"); ok {
		if p, err := strconv.Atoi(baud); err != nil {
			return err
		} else {
			conf.Baud = p
		}
	}
	if parity, ok := uci.GetLast("serial", section, "parity"); ok {
		if p, err := strconv.Atoi(parity); err != nil {
			return err
		} else {
			conf.Parity = uint8(p)
		}
	}
	if databit, ok := uci.GetLast("serial", section, "databit"); ok {
		if p, err := strconv.Atoi(databit); err != nil {
			return err
		} else {
			conf.DataBits = uint8(p)
		}
	}
	if stopbit, ok := uci.GetLast("serial", section, "stopbit"); ok {
		if p, err := strconv.Atoi(stopbit); err != nil {
			return err
		} else {
			conf.StopBits = uint8(p)
		}
	}
	return nil
}

func SaveSerialConfig(section string, conf *model.SerialPara) error {
	if conf == nil {
		return errors.New("config obj is nil")
	}
	if conf.Baud < 1200 || conf.Baud > 115200 ||
		conf.Parity > 3 || conf.DataBits < 5 || conf.DataBits > 8 ||
		(conf.StopBits != 1 && conf.StopBits != 2) {
		return errors.New("invalid para")
	}
	uci.Set("serial", section, "tcp_port", fmt.Sprint(conf.ListenPort))
	uci.Set("serial", section, "led", fmt.Sprint(conf.LedIO))
	uci.Set("serial", section, "baudrate", fmt.Sprint(conf.Baud))
	uci.Set("serial", section, "parity", fmt.Sprint(conf.Parity))
	uci.Set("serial", section, "databit", fmt.Sprint(conf.DataBits))
	uci.Set("serial", section, "stopbit", fmt.Sprint(conf.StopBits))
	_ = uci.Commit()
	return nil
}
